#include "gskglglyphcacheprivate.h"
#include "gskglrenderopsprivate.h"
#include "gskcairoblurprivate.h"
+#include "gskglshadowcacheprivate.h"
#include "gskprivate.h"
glGetUniformLocation(program_ptr->id, "u_" #uniform_basename);\
}G_STMT_END
-
static void G_GNUC_UNUSED
print_render_node_tree (GskRenderNode *root, int level)
{
GArray *render_ops;
GskGLGlyphCache glyph_cache;
+ GskGLShadowCache shadow_cache;
#ifdef G_ENABLE_DEBUG
struct {
int prev_render_target;
int texture_id, render_target;
int blurred_texture_id, blurred_render_target;
+ int cached_tid;
/* offset_outline is the minimal outline we need to draw the given drop shadow,
* enlarged by the spread and offset by the blur radius. */
texture_width = offset_outline.bounds.size.width + blur_extra;
texture_height = offset_outline.bounds.size.height + blur_extra;
- texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
- gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
- gsk_gl_driver_init_texture_empty (self->gl_driver, texture_id);
- render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture_id, FALSE, FALSE);
-
-
- graphene_matrix_init_ortho (&item_proj,
- 0, texture_width, 0, texture_height,
- ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
- graphene_matrix_scale (&item_proj, 1, -1, 1);
- graphene_matrix_init_identity (&identity);
+ cached_tid = gsk_gl_shadow_cache_get_texture_id (&self->shadow_cache,
+ self->gl_driver,
+ &offset_outline,
+ blur_radius);
+ if (cached_tid == 0)
+ {
+ texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
+ gsk_gl_driver_init_texture_empty (self->gl_driver, texture_id);
+ render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture_id, FALSE, FALSE);
+
+
+ graphene_matrix_init_ortho (&item_proj,
+ 0, texture_width, 0, texture_height,
+ ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
+ graphene_matrix_scale (&item_proj, 1, -1, 1);
+ graphene_matrix_init_identity (&identity);
+
+ prev_render_target = ops_set_render_target (builder, render_target);
+ op.op = OP_CLEAR;
+ ops_add (builder, &op);
+ prev_projection = ops_set_projection (builder, &item_proj);
+ prev_modelview = ops_set_modelview (builder, &identity);
+ prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
+
+ /* Draw outline */
+ ops_set_program (builder, &self->color_program);
+ prev_clip = ops_set_clip (builder, &offset_outline);
+ ops_set_color (builder, gsk_outset_shadow_node_peek_color (node));
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { 0, }, { 0, 1 }, },
+ { { 0, texture_height }, { 0, 0 }, },
+ { { texture_width, }, { 1, 1 }, },
- prev_render_target = ops_set_render_target (builder, render_target);
- op.op = OP_CLEAR;
- ops_add (builder, &op);
- prev_projection = ops_set_projection (builder, &item_proj);
- prev_modelview = ops_set_modelview (builder, &identity);
- prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
+ { { texture_width, texture_height }, { 1, 0 }, },
+ { { 0, texture_height }, { 0, 0 }, },
+ { { texture_width, }, { 1, 1 }, },
+ });
- /* Draw outline */
- ops_set_program (builder, &self->color_program);
- prev_clip = ops_set_clip (builder, &offset_outline);
- ops_set_color (builder, gsk_outset_shadow_node_peek_color (node));
- ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
- { { 0, }, { 0, 1 }, },
- { { 0, texture_height }, { 0, 0 }, },
- { { texture_width, }, { 1, 1 }, },
-
- { { texture_width, texture_height }, { 1, 0 }, },
- { { 0, texture_height }, { 0, 0 }, },
- { { texture_width, }, { 1, 1 }, },
- });
-
- blurred_texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
- gsk_gl_driver_bind_source_texture (self->gl_driver, blurred_texture_id);
- gsk_gl_driver_init_texture_empty (self->gl_driver, blurred_texture_id);
- blurred_render_target = gsk_gl_driver_create_render_target (self->gl_driver, blurred_texture_id, TRUE, TRUE);
-
- ops_set_render_target (builder, blurred_render_target);
- op.op = OP_CLEAR;
- ops_add (builder, &op);
+ blurred_texture_id = gsk_gl_driver_create_permanent_texture (self->gl_driver, texture_width, texture_height);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, blurred_texture_id);
+ gsk_gl_driver_init_texture_empty (self->gl_driver, blurred_texture_id);
+ blurred_render_target = gsk_gl_driver_create_render_target (self->gl_driver, blurred_texture_id, TRUE, TRUE);
- gsk_rounded_rect_init_from_rect (&blit_clip,
- &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height), 0.0f);
+ ops_set_render_target (builder, blurred_render_target);
+ op.op = OP_CLEAR;
+ ops_add (builder, &op);
- ops_set_program (builder, &self->blur_program);
- op.op = OP_CHANGE_BLUR;
- op.blur.size.width = texture_width;
- op.blur.size.height = texture_height;
- op.blur.radius = blur_radius;
- ops_add (builder, &op);
+ gsk_rounded_rect_init_from_rect (&blit_clip,
+ &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height), 0.0f);
- ops_set_clip (builder, &blit_clip);
- ops_set_texture (builder, texture_id);
- ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
- { { 0, 0 }, { 0, 1 }, },
- { { 0, texture_height }, { 0, 0 }, },
- { { texture_width, 0 }, { 1, 1 }, },
+ ops_set_program (builder, &self->blur_program);
+ op.op = OP_CHANGE_BLUR;
+ op.blur.size.width = texture_width;
+ op.blur.size.height = texture_height;
+ op.blur.radius = blur_radius;
+ ops_add (builder, &op);
- { { texture_width, texture_height }, { 1, 0 }, },
- { { 0, texture_height }, { 0, 0 }, },
- { { texture_width, 0 }, { 1, 1 }, },
- });
+ ops_set_clip (builder, &blit_clip);
+ ops_set_texture (builder, texture_id);
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { 0, 0 }, { 0, 1 }, },
+ { { 0, texture_height }, { 0, 0 }, },
+ { { texture_width, 0 }, { 1, 1 }, },
+ { { texture_width, texture_height }, { 1, 0 }, },
+ { { 0, texture_height }, { 0, 0 }, },
+ { { texture_width, 0 }, { 1, 1 }, },
+ });
- ops_set_clip (builder, &prev_clip);
- ops_set_viewport (builder, &prev_viewport);
- ops_set_modelview (builder, &prev_modelview);
- ops_set_projection (builder, &prev_projection);
- ops_set_render_target (builder, prev_render_target);
+ ops_set_clip (builder, &prev_clip);
+ ops_set_viewport (builder, &prev_viewport);
+ ops_set_modelview (builder, &prev_modelview);
+ ops_set_projection (builder, &prev_projection);
+ ops_set_render_target (builder, prev_render_target);
+
+ gsk_gl_shadow_cache_commit (&self->shadow_cache,
+ &offset_outline,
+ blur_radius,
+ blurred_texture_id);
+ }
+ else
+ {
+ blurred_texture_id = cached_tid;
+ }
ops_set_program (builder, &self->outset_shadow_program);
ops_set_texture (builder, blurred_texture_id);
}
}
-
- ops_set_clip (builder, &prev_clip);
}
static inline void
return FALSE;
gsk_gl_glyph_cache_init (&self->glyph_cache, renderer, self->gl_driver);
+ gsk_gl_shadow_cache_init (&self->shadow_cache);
return TRUE;
}
glDeleteProgram (self->programs[i].id);
gsk_gl_glyph_cache_free (&self->glyph_cache);
+ gsk_gl_shadow_cache_free (&self->shadow_cache, self->gl_driver);
g_clear_object (&self->gl_profiler);
g_clear_object (&self->gl_driver);
gsk_gl_driver_begin_frame (self->gl_driver);
gsk_gl_glyph_cache_begin_frame (&self->glyph_cache);
+ gsk_gl_shadow_cache_begin_frame (&self->shadow_cache, self->gl_driver);
memset (&render_op_builder, 0, sizeof (render_op_builder));
render_op_builder.renderer = self;
--- /dev/null
+
+#include "gskglshadowcacheprivate.h"
+
+typedef struct
+{
+ GskRoundedRect outline;
+ float blur_radius;
+} CacheKey;
+
+typedef struct
+{
+ int texture_id;
+ guint used : 1;
+} CacheValue;
+
+static gboolean
+key_equal (const void *x,
+ const void *y)
+{
+ const CacheKey *a = x;
+ const CacheKey *b = y;
+
+ return memcmp (&a->outline, &b->outline, sizeof (GskRoundedRect)) == 0 &&
+ a->blur_radius == b->blur_radius;
+}
+
+void
+gsk_gl_shadow_cache_init (GskGLShadowCache *self)
+{
+ self->textures = g_hash_table_new_full (g_direct_hash, key_equal, g_free, g_free);
+}
+
+void
+gsk_gl_shadow_cache_free (GskGLShadowCache *self,
+ GskGLDriver *gl_driver)
+{
+ g_hash_table_unref (self->textures);
+ self->textures = NULL;
+}
+
+void
+gsk_gl_shadow_cache_begin_frame (GskGLShadowCache *self,
+ GskGLDriver *gl_driver)
+{
+ GHashTableIter iter;
+ CacheKey *key;
+ CacheValue *value;
+
+ /* We remove all textures with used = FALSE since those have not been used in the
+ * last frame. For all others, we reset the `used` value to FALSE instead and see
+ * if they end up with TRUE in the next call to begin_frame. */
+
+ g_hash_table_iter_init (&iter, self->textures);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
+ {
+ if (!value->used)
+ {
+ /* Remove */
+ gsk_gl_driver_destroy_texture (gl_driver, value->texture_id);
+ g_hash_table_iter_remove (&iter);
+ }
+ else
+ {
+ value->used = FALSE;
+ }
+ }
+}
+
+/* XXX
+ * The offset origin should always be at 0/0, or the blur radius should just go
+ * away since it defines the origin position anyway?
+ */
+int
+gsk_gl_shadow_cache_get_texture_id (GskGLShadowCache *self,
+ GskGLDriver *gl_driver,
+ const GskRoundedRect *shadow_rect,
+ float blur_radius)
+{
+ CacheValue *value;
+
+ g_assert (self != NULL);
+ g_assert (gl_driver != NULL);
+ g_assert (shadow_rect != NULL);
+
+ value = g_hash_table_lookup (self->textures,
+ &(CacheKey){
+ *shadow_rect,
+ blur_radius
+ });
+
+ if (value == NULL)
+ return 0;
+
+ value->used = TRUE;
+
+ return value->texture_id;
+}
+
+void
+gsk_gl_shadow_cache_commit (GskGLShadowCache *self,
+ const GskRoundedRect *shadow_rect,
+ float blur_radius,
+ int texture_id)
+{
+ CacheKey *key;
+ CacheValue *value;
+
+ g_assert (self != NULL);
+ g_assert (shadow_rect != NULL);
+ g_assert (texture_id > 0);
+
+ key = g_new0 (CacheKey, 1);
+ key->outline = *shadow_rect;
+ key->blur_radius = blur_radius;
+
+ value = g_new0 (CacheValue, 1);
+ value->used = TRUE;
+ value->texture_id = texture_id;
+
+ g_hash_table_insert (self->textures, key, value);
+}